<!---
Copyright: (c) 2006 The MachBlog Authors
Authors: Matt Woodward (mpwoodward@gmail.com) & Peter J. Farrell (pjf@maestropublishing.com)

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

$Id$

Notes:
--->
<cfcomponent
	displayname="UserDAO"
	output="false"
	extends="UserDAO"
	hint="UserDAO for MachBlog (PostgreSQL)">

	<!---
	INITIALIZATION / CONFIGURATION
	--->
	<cffunction name="init" access="public" returntype="UserDAO" output="false"
		hint="Constructor for this CFC">
		<cfreturn this />
	</cffunction>

	<!---
	PUBLIC FUNCTIONS - CRUD
	--->
	<cffunction name="create" access="public" output="false" returntype="void" hint="Creates a new user">
		<cfargument name="user" type="User" required="true" />

		<cfset var insertUser = "" />

		<!--- check to see if the email address already exists --->
		<cfif emailExists(trim(arguments.user.getEmail()))>
			<cfthrow type="application" message="Duplicate Email" detail="Duplicate Email" />
		<cfelse>
			<!--- proceed with the user creation --->
			<cftry>
				<cfquery name="insertUser" datasource="#getDatasource().getDsn()#"
							username="#getDatasource().getUserName()#"
							password="#getDatasource().getPassword()#">
					INSERT INTO machblog_user (
						user_id
						, email
						, password
						, password_salt
						, first_name
						, last_name
						, created_by_id
						, dt_created
						, ip_created
						, is_active
					) VALUES (
						<cfqueryparam value="#arguments.user.getUserId()#" cfsqltype="cf_sql_char" maxlength="35" />
						, <cfqueryparam value="#trim(arguments.user.getEmail())#" cfsqltype="cf_sql_varchar" maxlength="100" />
						, <cfqueryparam value="#arguments.user.getPassword()#" cfsqltype="cf_sql_varchar" maxlength="50" />
						, <cfqueryparam value="#arguments.user.getPasswordSalt()#" cfsqltype="cf_sql_char" maxlength="35" />
						, <cfqueryparam value="#arguments.user.getFirstName()#" cfsqltype="cf_sql_varchar" maxlength="50" />
						, <cfqueryparam value="#arguments.user.getLastName()#" cfsqltype="cf_sql_varchar" maxlength="50" />
						, <cfqueryparam value="#arguments.user.getAudit().getCreatedById()#" cfsqltype="cf_sql_char" maxlength="35" />
						, <cfqueryparam value="#arguments.user.getAudit().getDtCreated()#" cfsqltype="cf_sql_bigint" />
						, <cfqueryparam value="#arguments.user.getAudit().getIpCreated()#" cfsqltype="cf_sql_varchar" maxlength="15" />
						, <cfqueryparam value="#arguments.user.getAudit().getIsActive()#" cfsqltype="cf_sql_smallint" />
					)
				</cfquery>
				<cfcatch type="database">
					<cfthrow type="application" message="Database Error" detail="#CFCATCH.Detail#" />
				</cfcatch>
			</cftry>
		</cfif>
	</cffunction>

	<cffunction name="read" access="public" output="false" returntype="void" hint="Retrieves a user">
		<cfargument name="user" type="User" required="true" />

		<cfset var getUser = "" />
		<cfset var cbName = "" />
		<cfset var mbName = "" />
		<cfset var dtLastAccess = 0 />
		<cfset var dtModified = 0 />
		<cfset var isHidden = 0 />
		<cfset var isActive = 0 />

		<cftry>
			<cfquery name="getUser" datasource="#getDatasource().getDsn()#"
						username="#getDatasource().getUserName()#"
						password="#getDatasource().getPassword()#">
				SELECT 	machblog_user.*,
						cb.first_name AS cbfn,
						cb.last_name AS cbln,
						mb.first_name AS mbfn,
						mb.last_name AS mbln
				FROM 	machblog_user
				LEFT OUTER JOIN machblog_user AS cb
					ON machblog_user.created_by_id = cb.user_id
				LEFT OUTER JOIN machblog_user AS mb
					ON machblog_user.modified_by_id = mb.user_id
				WHERE 	machblog_user.user_id = <cfqueryparam value="#arguments.user.getUserId()#"
															cfsqltype="cf_sql_char" maxlength="35" />
			</cfquery>
			<cfcatch type="database">
				<cfthrow type="application" message="Database Error" detail="#CFCATCH.Detail#" />
			</cfcatch>
		</cftry>

		<cfif IsQuery(getUser) AND getUser.RecordCount EQ 1>
			<cfset cbName = getUser.cbfn & " " & getUser.cbln />

			<cfif getUser.mbfn NEQ "">
				<cfset mbName = getUser.mbfn & " " & getUser.mbln />
			</cfif>

			<cfif getUser.dt_last_access NEQ "">
				<cfset dtLastAccess = getUser.dt_last_access />
			</cfif>

			<cfif getUser.dt_modified NEQ "">
				<cfset dtModified = getUser.dt_modified />
			</cfif>

			<cfif getUser.is_active NEQ "">
				<cfset isActive = getUser.is_active />
			</cfif>

			<cfset arguments.user.init(getUser.user_id, getUser.email, getUser.password,
										getUser.password_salt, getUser.first_name, getUser.last_name,
										dtLastAccess, getUser.ip_last_access) />

			<cfset arguments.user.getAudit().init(getUser.created_by_id, cbName, getUser.dt_created,
													getUser.ip_created, getUser.modified_by_id,
													mbName, dtModified, getUser.ip_modified, isHidden, isActive) />
		</cfif>
	</cffunction>

	<cffunction name="update" access="public" output="false" returntype="void" hint="Updates a user">
		<cfargument name="user" type="User" required="true" />

		<cfset var updateUser = "" />

		<!--- check to see if the email address being used in the update matches the account's existing email, and if not,
				double-check to make sure it isn't a duplicate email --->
		<cfif isEmailAddressChange(arguments.user.getUserId(), trim(arguments.user.getEmail())) AND emailExists(trim(arguments.user.getEmail()))>
			<cfthrow type="application" message="Duplicate Email" detail="Duplicate Email" />
		<cfelse>
			<!--- proceed with the update --->
			<cftry>
				<cfquery name="updateUser" datasource="#getDatasource().getDsn()#"
							username="#getDatasource().getUserName()#"
							password="#getDatasource().getPassword()#">
					UPDATE 	machblog_user
					SET 	email = <cfqueryparam value="#arguments.user.getEmail()#"
													cfsqltype="cf_sql_varchar" maxlength="100" />,
						<cfif arguments.user.getPassword() NEQ "">
							password = <cfqueryparam value="#arguments.user.getPassword()#"
													cfsqltype="cf_sql_varchar" maxlength="50" />,
						</cfif>
							first_name = <cfqueryparam value="#arguments.user.getFirstName()#"
													cfsqltype="cf_sql_varchar" maxlength="50" />,
							last_name = <cfqueryparam value="#arguments.user.getLastName()#"
													cfsqltype="cf_sql_varchar" maxlength="50" />,
							modified_by_id = <cfqueryparam value="#arguments.user.getAudit().getModifiedById()#"
													cfsqltype="cf_sql_char" maxlength="35" />,
							dt_modified = <cfqueryparam value="#arguments.user.getAudit().getDtModified()#"
													cfsqltype="cf_sql_bigint" />,
							ip_modified = <cfqueryparam value="#arguments.user.getAudit().getIpModified()#"
													cfsqltype="cf_sql_varchar" maxlength="15" />,
							is_active = <cfqueryparam value="#arguments.user.getAudit().getIsActive()#" cfsqltype="cf_sql_smallint" />
					WHERE 	user_id = <cfqueryparam value="#arguments.user.getUserId()#"
													cfsqltype="cf_sql_char" maxlength="35" />
				</cfquery>
				<cfcatch type="database">
					<cfthrow type="application" message="Database Error" detail="#CFCATCH.Detail#" />
				</cfcatch>
			</cftry>
		</cfif>
	</cffunction>

	<cffunction name="delete" access="public" output="false" returntype="void"
			hint="Deletes a user and that user's entries and comments">
		<cfargument name="user" type="User" required="true" />

		<cfset var deleteUser = "" />
		<cfset var deleteEntries = "" />
		<cfset var deleteComments = "" />

		<cftry>
			<cfquery name="deleteUser" datasource="#getDatasource().getDsn()#"
						username="#getDatasource().getUserName()#"
						password="#getDatasource().getPassword()#">
				DELETE FROM machblog_user
				WHERE user_id = <cfqueryparam value="#arguments.user.getUserId()#"
												cfsqltype="cf_sql_char" maxlength="35" />
			</cfquery>
			<cfcatch type="database">
				<cfthrow type="application" message="Database Error" detail="#CFCATCH.Detail#" />
			</cfcatch>
		</cftry>
	</cffunction>

	<cffunction name="emailExists" access="private" output="false" returntype="boolean"
			hint="Checks to see if an email address already exists">
		<cfargument name="email" type="string" required="true" />

		<cfset var checkEmail = "" />
		<cfset var emailExists = true />

		<cftry>
			<cfquery name="checkEmail" datasource="#getDatasource().getDsn()#"
						username="#getDatasource().getUserName()#"
						password="#getDatasource().getPassword()#">
				SELECT user_id
				FROM machblog_user
				WHERE email = <cfqueryparam value="#arguments.email#" cfsqltype="cf_sql_varchar" maxlength="100" />
			</cfquery>
			<cfcatch type="database">
				<cfthrow type="application" message="Database Error" detail="#CFCATCH.Detail#" />
			</cfcatch>
		</cftry>

		<cfif isQuery(checkEmail) AND checkEmail.RecordCount EQ 0>
			<cfset emailExists = false />
		</cfif>

		<cfreturn emailExists />
	</cffunction>

	<cffunction name="isEmailAddressChange" access="private" output="false" returntype="boolean"
			hint="Checks to see if the email address associated with an account is being changed on a user update">
		<cfargument name="userId" type="uuid" required="true" />
		<cfargument name="email" type="string" required="true" />

		<cfset var emailChange = true />
		<cfset var checkEmail = "" />

		<cftry>
			<cfquery name="checkEmail" datasource="#getDatasource().getDsn()#"
						username="#getDatasource().getUserName()#"
						password="#getDatasource().getPassword()#">
				SELECT 	email
				FROM 	machblog_user
				WHERE 	user_id = <cfqueryparam value="#arguments.userId#" cfsqltype="cf_sql_char" maxlength="35" />
			</cfquery>
			<cfcatch type="database">
				<cfthrow type="application" message="Database Error" detail="#CFCATCH.Detail#" />
			</cfcatch>
		</cftry>

		<cfif isQuery(checkEmail) AND checkEmail.RecordCount GT 0>
			<cfif arguments.email EQ checkEmail.email>
				<cfset emailChange = false />
			</cfif>
		</cfif>

		<cfreturn emailChange />
	</cffunction>
</cfcomponent>